package pl.donajski.magisterka;

import java.util.List;

public class TabuSearch {
	private int mValidateRatio;
	public TabuSearch(State initialState, IMoveGenerator mg, ITabuList tl, int nLoops, int mainLoops, int validateRatio) {
		this.mState = initialState;
		this.mBestCost = this.mState.getCost();
		this.mMovesGenerator = mg;
		this.mTabuList = tl;
		this.mMainLoops = mainLoops;
		this.mNLoops = nLoops;
		this.mValidateRatio = validateRatio;
	}
	
	public int solve() {
		return this.go();
	}
	
	private int go() {
		int last = 0;
		for(int t = 0 ; t <= this.mMainLoops; ++t) {
			
			//this.printProgress(t);
			
			IMove m = this.getAcceptableMove();
			this.mState.move(m);
			
			//System.out.println(this.mState.getCost());
			//System.out.println(this.mState.getValidness());
			mTabuList.add(m);
			
			if(t - last == this.mValidateRatio) {
				last = t;
				this.mState.fixState();
			}
			
			if(this.mState.isValid() && this.mState.getCost() < this.mBestCost) {
				last = t;
				//this.mState.setFlows();
				//this.mState.calculateCost();
				//System.out.println(this.mState.getFlowsCost() + "\t" + this.mState.getProcessingCost());
				this.mBestCost = this.mState.getCost();	
			}
		}
		return this.mBestCost;
	}

	private void printProgress(int t) {
		this.progressCurr = (100*(t + 1)) / this.mMainLoops;
		
		if(this.progressCurr != this.progressPrev)
			System.out.println(progressCurr + "%");
		this.progressPrev = this.progressCurr;
		
	}

	private IMove getAcceptableMove() {
		//TODO: clone rather than copy ref
		IMove currMove = null;
		IMove bestMove = null;
		int bestCost   = Integer.MAX_VALUE;
		int currCost   = 0;
		for(int t = 0 ; t < this.mNLoops || bestMove == null ; ++t) {
			currMove = mMovesGenerator.getRandomMove();
			
			if(mTabuList.contains(currMove))
				continue;
			
			currCost = this.mState.getCostAfterMove(currMove) + this.mState.getPenaltyAfterMove(currMove);
					
			if(currCost < bestCost) {
				bestCost = currCost;
				bestMove = currMove.clone();
			}
		}
		if(App._debug)
			System.out.println("Best cost: " + bestCost);
		return bestMove;
	}

	private IMoveGenerator mMovesGenerator;
	private State mState;
	private ITabuList mTabuList;
	private int mBestCost;
	private int progressPrev = 0;
	private int progressCurr = 0;
	private int mNLoops = 0;
	private int mMainLoops = 0;
	
	
	private static final int MAIN_ITERATIONS 	   = 50000;
	private static final int NEIGHBOURS_ITERATIONS = 1000;
}
